package com.zrc.superframe_net.utils

import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.Uri
import android.os.Build
import android.os.Environment
import androidx.core.content.FileProvider
import com.blankj.utilcode.util.NetworkUtils
import com.zrc.superframe_net.common.net.Net
import com.zrc.superframe_net.room.download.DownloadInfo
import okhttp3.ResponseBody
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.nio.channels.FileChannel
import kotlin.concurrent.thread

/**
 * @Author: superman
 * @CreateTime: 6/27/21
 * @Describe:文件操作类
 */
class NetUtils(val mContext: Context, private val mApplictionId: String?) {
    private var netIsAvailable = false

    lateinit var netType : NetworkUtils.NetworkType

    lateinit var context: Context

    var observable = object : NetworkUtils.OnNetworkStatusChangedListener {

        override fun onDisconnected() {//网络状态变更时时监听
            isAvailable()
        }

        override fun onConnected(networkType: NetworkUtils.NetworkType) {
            this@NetUtils.netType=networkType
            isAvailable()
        }

    }

    init {
        NetworkUtils.registerNetworkStatusChangedListener(observable)
        isAvailable()
    }

    companion object {

        lateinit var instance: NetUtils

        fun init(context: Context, applictionId: String?): NetUtils? {
            if (!this::instance.isInitialized) {
                instance = NetUtils(context, applictionId)
            }
            return instance
        }
    }

    fun destroy(){
        NetworkUtils.unregisterNetworkStatusChangedListener(observable)
    }

    //描述：判断网络是否有效.
    fun isNetworkAvailable(): Boolean {
        try {
            val connectivity =
                mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            if (connectivity != null) {
                val info = connectivity.activeNetworkInfo
                if (info != null && info.isConnected) {
                    if (info.state == NetworkInfo.State.CONNECTED) {
                        return true
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            return false
        }
        return false
    }//判断SDK存不存在

    //下载文件保存路径
    fun downloadDirectory(): File {//判断SDK存不存在
        return if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
        } else {
            Environment.getDownloadCacheDirectory()
        }
    }

    //写入文件    异步下载时，写入
    @Throws(IOException::class)
    fun writeCache(responseBody: ResponseBody, file: File, info: DownloadInfo) {
        if (!file.parentFile.exists()) {
            file.mkdirs()
        }
        var allLength = info.countLength
        if (allLength == 0L) {
            allLength = responseBody.contentLength()
        }
        val randomAccessFile = RandomAccessFile(file, "rwd")
        val channelOut = randomAccessFile.channel
        val mappedBuffer = channelOut.map(
            FileChannel.MapMode.READ_WRITE,
            info.readLength,
            allLength - info.readLength
        )
        val inputStream = responseBody.byteStream()
        val buffer = ByteArray(1024 * 8)
        var len: Int
        while (inputStream.read(buffer).also { len = it } != -1) {
            mappedBuffer.put(buffer, 0, len)
        }
        //关闭流
        inputStream.close()
        channelOut.close()
        randomAccessFile.close()
    }

    //安装apk
    fun installApk(path: String?) {
        val apkFile = File(path)
        if (!apkFile.exists()) {
            return
        }
        val intent = Intent(Intent.ACTION_VIEW)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive")
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        } else {
            intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION// 声明需要的临时权限
            val contentUri =
                FileProvider.getUriForFile(mContext, "$mApplictionId.fileProvider", apkFile)// 第二个参数，即第一步中配置的authorities
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
        }
        mContext.startActivity(intent)
    }

    //用ping判断网络是否可用 传入callbacks可以异步回调 不传也可以但是没有异步效果会导致获取的值不准确
    private fun isAvailable(callbacks: ((isOk:Boolean)->Unit)?=null) {
        thread {
            netIsAvailable = NetworkUtils.isAvailableByPing()
            callbacks?.let { it(netIsAvailable) }
            Net.log("net_isconnect -> $netIsAvailable")
        }
    }

    //异步判断网络是否可用
    fun isNetConnectAsync(callbacks: (isOk:Boolean)->Unit)= isAvailable(callbacks)

    //判断网络是否可用(该状态是初始化获取的，随着用户手机网络状态变化，该值也会变化，但是时时性不高，对时时性要求较高的建议使用isNetConnectAsync)
    fun isNetConnect()=netIsAvailable

    //获取当前网络状态
    fun getNetWorkType()=if (!this::netType.isInitialized) NetworkUtils.NetworkType.NETWORK_NO else netType

    @Throws(Exception::class)
    private fun getSystemProperty(name: String): String {
        val systemPropertyClazz = Class.forName("android.os.SystemProperties")
        return systemPropertyClazz.getMethod("get", String::class.java)
            .invoke(systemPropertyClazz, name) as String
    }

    //是否是模拟器(true:为模拟器：false：为真机)
    private fun isEmulator(): Boolean {
        try {
            val goldfish = getSystemProperty("ro.hardware").contains("goldfish")
            val emu = getSystemProperty("ro.kernel.qemu").isNotEmpty()
            val sdk = getSystemProperty("ro.product.model") == "sdk"
            if (emu || goldfish || sdk) {
                return true
            }
        } catch (e: Exception) {
        }
        return false
    }
}